#pragma once

#include <functional>
#include <pthread.h>

#include "Socket.hpp"
#include "ThreadPool.hpp"

using func_t_1 = std::function<std::string(std::string &, std::string, uint16_t, bool *)>;
using tasks = std::function<void()>;

static const int Tcp_read_default_Size = 1024;

class TcpServer;

class ThreadData
{
    TcpServer *_tcp_server;
    Net_work::Socket *_socket;
    std::string _ip;
    uint16_t _port;

public:
    ThreadData(TcpServer *tcp_server, Net_work::Socket *socket, std::string &ip, uint16_t port)
        : _tcp_server(tcp_server), _socket(socket), _ip(ip), _port(port)
    {
    }

    ~ThreadData()
    {
    }

    TcpServer *get_tcp_server()
    {
        return _tcp_server;
    }

    Net_work::Socket *get_socket()
    {
        return _socket;
    }

    std::string get_ip()
    {
        return _ip;
    }

    uint16_t get_port()
    {
        return _port;
    }
};

class TcpServer
{
    int _port;
    Net_work::Socket *_listensocket;

public:
    func_t_1 _func_t;

public:
    TcpServer(uint16_t port, func_t_1 __func_t) : _port(port), _func_t(__func_t), _listensocket(new Net_work::TcpSocket())
    {
        _listensocket->BuildListenSocket(port, Net_work::backlog);

        // 创建线程池
        ThreadNs::ThreadPool<tasks>::GetInstance()->Start();
    }

    ~TcpServer()
    {
        delete _listensocket;
    }

    static void ThreadRun(void *arg)
    {
        pthread_detach(pthread_self());
        ThreadData *data = static_cast<ThreadData *>(arg);

        std::string inbufferstream;

        while (true)
        {

            if (!data->get_socket()->Recv(&inbufferstream, Tcp_read_default_Size))
                break; // 只有将缓冲区读取干净才会退出
            
            

            bool flag;

            // 调用函数 func_t 构造函数传参进来的
            std::string Sum_Message = data->get_tcp_server()->_func_t(inbufferstream, data->get_ip(), data->get_port(), &flag);
            if(flag)
            {
               
                if(!Sum_Message.size()==0)
                {
                    // 在 Socket 中，封装了 文件描述符，直接给出需要写的报文即可
                    data->get_socket()->Send(Sum_Message);
                }
            }
            else
            {
                // 报文解析出现问题，直接退出
                break;
            }
        
        }

        // 处理完毕关闭 文件描述符
        data->get_socket()->CloseSocket();
        delete data->get_socket();
        delete data;
    }

    void Loop()
    {
        while (true)
        {

            std::string peerip;
            uint16_t peerport;

            Net_work::Socket *newsock = _listensocket->AcceptConnection(&peerip, &peerport);
            if (newsock == nullptr)
                continue;

            std::cout << "get a new connection,sockfd: " << newsock->GetSockFd() << " client info: "
                      << peerip << ":" << peerport << std::endl;

            // pthread_t tid;
            // pthread_create(&tid, nullptr, ThreadRun, new ThreadData(this, newsock, peerip, peerport));

            tasks t = std::bind(&TcpServer::ThreadRun, (void *)new ThreadData(this, newsock, peerip, peerport));

            ThreadNs::ThreadPool<tasks>::GetInstance()->Push(t);
        }
    }
};

// #pragma once

// #include <iostream>
// #include <string>
// #include <cstring>
// #include <sys/types.h>
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>
// #include <unistd.h>

// #define Convert(addrptr) ((struct sockaddr *)addrptr)

// namespace Net_Work
// {
//     const static int defaultsockfd = -1;
//     const int backlog = 5;

//     enum
//     {
//         SocketError = 1,
//         BindError,
//         ListenError,
//     };

//     // 封装一个基类，Socket接口类
//     // 设计模式：模版方法类
//     class Socket
//     {
//     public:
//         virtual ~Socket() {}
//         virtual void CreateSocketOrDie() = 0;
//         virtual void BindSocketOrDie(uint16_t port) = 0;
//         virtual void ListenSocketOrDie(int backlog) = 0;
//         virtual Socket *AcceptConnection(std::string *peerip, uint16_t *peerport) = 0;
//         virtual bool ConnectServer(std::string &serverip, uint16_t serverport) = 0;
//         virtual int GetSockFd() = 0;
//         virtual void SetSockFd(int sockfd) = 0;
//         virtual void CloseSocket() = 0;
//         // TODO
//     public:
//         void BuildListenSocketMethod(uint16_t port, int backlog)
//         {
//             CreateSocketOrDie();
//             BindSocketOrDie(port);
//             ListenSocketOrDie(backlog);
//         }
//         bool BuildConnectSocketMethod(std::string &serverip, uint16_t serverport)
//         {
//             CreateSocketOrDie();
//             return ConnectServer(serverip, serverport);
//         }
//         void BuildNormalSocketMethod(int sockfd)
//         {
//             SetSockFd(sockfd);
//         }
//     };

//     class TcpSocket : public Socket
//     {
//     public:
//         TcpSocket(int sockfd = defaultsockfd) : _sockfd(sockfd)
//         {
//         }
//         ~TcpSocket()
//         {
//         }
//         void CreateSocketOrDie() override
//         {
//             _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
//             if (_sockfd < 0)
//                 exit(SocketError);
//         }
//         void BindSocketOrDie(uint16_t port) override
//         {
//             struct sockaddr_in local;
//             memset(&local, 0, sizeof(local));
//             local.sin_family = AF_INET;
//             local.sin_addr.s_addr = INADDR_ANY;
//             local.sin_port = htons(port);

//             int n = ::bind(_sockfd, Convert(&local), sizeof(local));
//             if (n < 0)
//                 exit(BindError);
//         }
//         void ListenSocketOrDie(int backlog) override
//         {
//             int n = ::listen(_sockfd, backlog);
//             if (n < 0)
//                 exit(ListenError);
//         }
//         Socket *AcceptConnection(std::string *peerip, uint16_t *peerport) override
//         {
//             struct sockaddr_in peer;
//             socklen_t len = sizeof(peer);
//             int newsockfd = ::accept(_sockfd, Convert(&peer), &len);
//             if (newsockfd < 0)
//                 return nullptr;
//             *peerport = ntohs(peer.sin_port);
//             *peerip = inet_ntoa(peer.sin_addr);
//             Socket *s = new TcpSocket(newsockfd);
//             return s;
//         }
//         bool ConnectServer(std::string &serverip, uint16_t serverport) override
//         {
//             struct sockaddr_in server;
//             memset(&server, 0, sizeof(server));
//             server.sin_family = AF_INET;
//             server.sin_addr.s_addr = inet_addr(serverip.c_str());
//             server.sin_port = htons(serverport);

//             int n = ::connect(_sockfd, Convert(&server), sizeof(server));
//             if (n == 0)
//                 return true;
//             else
//                 return false;
//         }
//         int GetSockFd() override
//         {
//             return _sockfd;
//         }
//         void SetSockFd(int sockfd) override
//         {
//             _sockfd = sockfd;
//         }
//         void CloseSocket() override
//         {
//             if (_sockfd > defaultsockfd)
//                 ::close(_sockfd);
//         }

//     private:
//         int _sockfd;
//     };

// }
